home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / WindowLib / WindowLib.c < prev    next >
Encoding:
Text File  |  1994-01-14  |  31.4 KB  |  1,112 lines  |  [TEXT/KAHL]

  1. /*    Functions for doing things to windows. Included are functions for validating
  2.     a window, accessing and setting common window fields (to avoid directly
  3.     referencing fields in a window record), positioning a window according
  4.     to the Human Interface Notes (HIN), saving and restoring a window's
  5.     position, creating and disposing of a window, and various other
  6.     miscelanous functions. A window created by this library also has some
  7.     extra fields added to it which support proper positioning, zooming,
  8.     and saving/restoring the window's position.
  9.     
  10.     Also supported are multiple window layers, including floating windoids.
  11.     Currently, there are three layers: the regular document layer, a
  12.     floating windoid layer, and a modal dialog layer. Document windows
  13.     always fall behind any floating windows, and floating windows always
  14.     fall behind any modal windows. System windows can come in front of
  15.     any window layer, but normally can not be selected when a modal dialog
  16.     is front most (since that would violate the HIG). Window layers are
  17.     assigned automatically when a window is created based on its procID.
  18.     Window layers would have been simpler to implement if there was some
  19.     way to disable the generation of activate events for certain windows,
  20.     to disable automatic window hiliting (automatic window hiliting is
  21.     disabled using a patch), and to ignore system windows. Much of the
  22.     complexity of window layers is due solely to system windows. System
  23.     windows can be ignored under MultiFinder, but under Finder they must
  24.     be accommadated. 
  25.     
  26.     Notice:    The window positioning and zooming functions have been moved to
  27.                 separate files.
  28.                 
  29.     Revision History:
  30.  
  31.     94/01/08 aih
  32.     - added function to determine if a window is entirely visible, and
  33.     added a postcondition to WinShow that ensures that a window is properly
  34.     positioned
  35.     - moved several window positioning and sizing related functions to
  36.     WindowPositionLib.c
  37.     - strengthened a few pre- and postconditions
  38.     
  39.     93/12/16 aih
  40.     - added some comments
  41.     
  42.     93/12/07 aih
  43.     - added support for my windoid WDEF's variation codes
  44.     
  45.     93/12/02 aih
  46.     - changed function for dragging windows to use a library function of mine
  47.     rather than DragGrayRgn
  48.     
  49.     93/12/01 aih
  50.     - improved calculation of structure and content rectangles for invisible
  51.     windows
  52.     - improved calculation of rectangle for new windows
  53.     - improved zoom functions (a few days ago)
  54.     
  55.     93/11/15 aih
  56.     - continuing development of window layers to work properly with system
  57.     windows
  58.     - drag outline for a window is clipped to the windows above it
  59.     - if in pre-7.0 system and using a movable modal dialog then
  60.     a special WDEF (released by MacDTS) is substituted for WDEF 0.
  61.     - improved dialog creation code
  62.     - program_note:    the functions that use GetWVariant to determine window
  63.                             characteristics won't work with windows that don't
  64.                             use the standard variants or variants I've programmed
  65.                             in for them.
  66.                             
  67.     93/11/12 aih
  68.     - added window layers (again...)
  69.     
  70.     93/11/03 aih
  71.     - the extra window information is stored in a handle instead of a pointer
  72.     
  73.     93/10/25 aih
  74.     - removed unused functions
  75.     
  76.     93/03/14 AIH
  77.     - Removed most of window layer code since it just wasn't working
  78.     
  79.     93/03/06 AIH
  80.     - A check-mark is placed next to the current window
  81.     
  82.     93/03/05 AIH
  83.     - Added functions for hiding a window, activating/deactiving all windows
  84.     in a layer (especially useful when displaying modal dialogs and when
  85.     suspending and resuming the application)
  86.     
  87.     92/05/24 AIH
  88.     - Fixed some problems with floating windows
  89.     
  90.     92/03/06 AIH
  91.     - Added support for multiple window layers, such as document
  92.     and pallete windows
  93.     
  94.     92/03/02 AIH
  95.     - Changed extra window data into a pointer which is saved in
  96.     the window's refCon field. This simplified a lot of the code.
  97.     Thanks goodness for data hiding! It made modifying this
  98.     library a breeze.
  99.     
  100.     92/03/01 AIH
  101.     - Got rid of unused window kinds
  102.     
  103.     92/02/26 AIH
  104.     - Added function to determine if the front window is modal
  105.     - Added function to determine if a window has a go away box
  106.     - Added tab object list
  107.     
  108.     92/02/21 AIH
  109.     - New windows are registered with the event library and unregistered
  110.     when destroyed
  111.     
  112.     91/07/03 AIH
  113.     - Clarified a few comments
  114.     - The window validation function accepts a flag to indicate if the window
  115.     has to have been created by this library
  116.     
  117.     91/06/13 AIH
  118.     - Added functions for getting the first window in the window list
  119.     and the first visible window in the window list. These may be adapted
  120.     in the future to support floating windows.
  121.     - Changed name of the function "WinRect" to better describe its purpose
  122.     
  123.     91/06/01 AIH
  124.     - A color window is created from a window template if the Macintosh supports
  125.     color
  126.     - The window's size rectangle is initialized when a window is created
  127.     - Added function to handle setting a window's zoom state given a prefered
  128.     size for the window
  129.     
  130.     91/05/29 AIH
  131.     - Added a constant size option to the window staggering function
  132.     
  133.     91/05/28 AIH
  134.     - A color window is created if the machine supports color
  135.     
  136.     91/05/19-20 AIH
  137.     - The staggering algorithm is more elegant
  138.     
  139.     91/05/18 AIH
  140.     - Fixed a mistake in the stagger window function
  141.     
  142.     91/05/14 AIH
  143.     - Still working on getting window states to be remembered correctly
  144.     
  145.     91/05/12 AIH
  146.     - The current screen is used, instead of just the main screen
  147.     - Window size and position are remembered and set more in accordance
  148.     with the HIN
  149.     - Added function to stagger a window
  150.     
  151.     91/05/09 AIH
  152.     - Added a function for determining if a window is an event window
  153.     - Added function to return next window in window list
  154.     
  155.     91/05/07 AIH
  156.     - To avoid drawing the grow icon twice when an activate event
  157.     is followed by an update event we validate the grow icon's rectangle
  158.     after it is drawn.
  159.     
  160.     91/04/26 AIH
  161.     - Added zoomDocProc to list of windows with drag regions, and added a
  162.     function to determine if a window has a grow region
  163.     - Added functions for saving and restoring window states
  164.     
  165.     91/04/10 AIH
  166.     - Added some "standard" window kinds
  167.     
  168.     91/04/07 AIH
  169.     - Added function to determine if a window needs updating
  170.     
  171.     91/03/26 AIH
  172.     - Got rid of WIN_MODAL_KIND since it wasn't needed and only complicated
  173.     the code
  174.     - Got rid of WIN_MOVABLE_MODAL since it has the (obvious) official
  175.     name "movableDBoxProc"
  176.     
  177.     91/03/23 AIH
  178.     - Added function to return a window's position (from EventLib)
  179.     - Added function to determine if a window can be dragged (from DialogLib)
  180.     
  181.     91/03/14 AIH
  182.     - Added function to draw the grow icon
  183.     
  184.     91/03/10 Ari Halberstadt (AIH)
  185.     - Created this library */
  186.  
  187. #include <string.h>
  188. #include <stdlib.h>
  189. #include "DrawLib.h"
  190. #include "LowMemLib.h"
  191. #include "MacLib.h"
  192. #include "MemoryLib.h"
  193. #include "PatchLib.h"
  194. #include "RectangleLib.h"
  195. #include "ResourceConstantsLib.h"
  196. #include "ResourceLib.h"
  197. #include "ScreenLib.h"
  198. #include "StringLib.h"
  199. #include "SystemWindowLib.h"
  200. #include "WindoidWDEF.h"
  201. #include "WindowLib.h"
  202.  
  203. static WindowPtr gLayers[WIN_LAYER_LAST];    /* lists of windows in each layer */
  204. static PatchType *gPatchHiliteWindow;        /* data for patch to HiliteWindow */
  205.  
  206. /*----------------------------------------------------------------------------*/
  207. /* window validation */
  208. /*----------------------------------------------------------------------------*/
  209.  
  210. /* true if valid window layer */
  211. static Boolean WinLayerValid(WindowLayerType layer)
  212. {
  213.     return(WIN_LAYER_NONE < layer && layer < WIN_LAYER_LAST);
  214. }
  215.  
  216. /* true if window is a valid window */
  217. Boolean WinValid(WindowPtr window)
  218. {
  219.     if (! MemValid(window)) return(false);
  220.     if (((WindowPeek)window)->windowKind <= userKind) return(true);
  221.     if (! PtrValidSize(window, sizeof(WindowRecord))) return(false);
  222.     return(true);
  223. }
  224.  
  225. /*----------------------------------------------------------------------------*/
  226. /* extra data */
  227. /*----------------------------------------------------------------------------*/
  228.  
  229. /* return handle to extra window data */
  230. WindowExtraHandle WinExtraHandle(WindowPtr window)
  231. {
  232.     WindowExtraHandle extra = NULL;
  233.     
  234.     require(WinKind(window) >= WIN_KIND_EXTRA);
  235.     extra = (WindowExtraHandle) GetWRefCon(window);
  236.     ensure(HandleValidSize(extra, sizeof(WindowExtraType)));
  237.     return(extra);
  238. }
  239.  
  240. /* Return pointer to extra window data. Warning: pointer is
  241.     dereferenced handle, memory may move! */
  242. WindowExtraPtr WinExtraPtr(WindowPtr window)
  243. {
  244.     return(*WinExtraHandle(window));
  245. }
  246.  
  247. /* set the window's extra data */
  248. static void WinExtraSet(WindowPtr window, WindowExtraHandle extra)
  249. {
  250.     require(WinKind(window) >= WIN_KIND_EXTRA);
  251.     (**extra).window = window;
  252.     SetWRefCon(window, (long) extra);
  253.     ensure(WinValid(window));
  254. }
  255.  
  256. /*----------------------------------------------------------------------------*/
  257. /* application defined data */
  258. /*----------------------------------------------------------------------------*/
  259.  
  260. void *WinData(WindowPtr window)
  261. {
  262.     return(WinExtraPtr(window)->data);
  263. }
  264.  
  265. void WinDataSet(WindowPtr window, void *data)
  266. {
  267.     WinExtraPtr(window)->data = data;
  268. }
  269.  
  270. /*----------------------------------------------------------------------------*/
  271. /* window properties and attributes */
  272. /*----------------------------------------------------------------------------*/
  273.  
  274. /* true if the window is visible */
  275. Boolean WinVisible(WindowPtr window)
  276. {
  277.     require(WinValid(window));
  278.     return(((WindowPeek)window)->visible != 0);
  279. }
  280.  
  281. /* true if the entire window is visible */
  282. Boolean WinVisibleFully(WindowPtr window)
  283. {
  284.     RgnHandle structureRgn;
  285.     Boolean result = false;
  286.     
  287.     if (WinVisible(window)) {
  288.         structureRgn = BeginRgn();
  289.         CopyRgn(((WindowPeek) window)->strucRgn, structureRgn);
  290.         SectRgn(GetGrayRgn(), structureRgn, structureRgn);
  291.         result = EqualRgn(((WindowPeek) window)->strucRgn, structureRgn);
  292.         EndRgn(structureRgn);
  293.     }
  294.     return(result);    
  295. }
  296.  
  297. /* return the window's windowKind field */
  298. short WinKind(WindowPtr window)
  299. {
  300.     require(WinValid(window));
  301.     return(((WindowPeek)window)->windowKind);
  302. }
  303.  
  304. /* set the window's windowKind field */
  305. void WinKindSet(WindowPtr window, short kind)
  306. {
  307.     require(WinValid(window));
  308.     ((WindowPeek)window)->windowKind = kind;
  309. }
  310.  
  311. /* true if window is a system window */
  312. Boolean WinIsSystem(WindowPtr window)
  313. {
  314.     require(WinValid(window));
  315.     return(WinKind(window) < 0);
  316. }
  317.  
  318. /* true if window is a dialog window */
  319. Boolean WinIsDialog(WindowPtr window)
  320. {
  321.     require(WinValid(window));
  322.     return(WinKind(window) == dialogKind ||
  323.              (WinHasExtra(window) && WinExtraPtr(window)->dialog));
  324. }
  325.  
  326. /* true if window is a user window */
  327. Boolean WinIsUser(WindowPtr window)
  328. {
  329.     require(WinValid(window));
  330.     return(WinKind(window) >= userKind);
  331. }
  332.  
  333. /* true if window is a floating window */
  334. Boolean WinIsFloat(WindowPtr window)
  335. {
  336.     return(WinHasExtra(window) && WinLayer(window) == WIN_LAYER_FLOAT);
  337. }
  338.  
  339. /* true if window is modal */
  340. Boolean WinIsModal(WindowPtr window)
  341. {
  342.     Boolean result = false;
  343.     
  344.     require(WinValid(window));
  345.     if (! WinIsFloat(window)) {
  346.         switch (GetWVariant(window)) {
  347.         case dBoxProc:
  348.         case movableDBoxProc:
  349.             result = true;
  350.             break;
  351.         }
  352.     }
  353.     return(result);
  354. }
  355.  
  356. /* true a modal window has the input focus, or if the front window
  357.     is a modal window (e.g., a standard file dialog) */
  358. Boolean WinModalHasFocus(void)
  359. {
  360.     return((FocusWindow() && WinIsModal(FocusWindow())) ||
  361.              (FrontWindow() && WinIsModal(FrontWindow())));
  362. }
  363.  
  364. /* true if the window has extra information */
  365. Boolean WinHasExtra(WindowPtr window)
  366. {
  367.     return(WinKind(window) >= WIN_KIND_EXTRA && WinExtraHandle(window) != NULL);
  368. }
  369.  
  370. /* true if the window has a go away box */
  371. Boolean WinHasGoAway(WindowPtr window)
  372. {
  373.     require(WinValid(window));
  374.     return(((WindowPeek) window)->goAwayFlag);
  375. }
  376.  
  377. /* true if window has a grow region */
  378. Boolean WinHasGrow(WindowPtr window)
  379. {
  380.     Boolean result = false;
  381.     
  382.     require(WinValid(window));
  383.     if (WinIsFloat(window))
  384.         result = WindoidHasGrow(window);
  385.     else switch(GetWVariant(window)) {
  386.     case documentProc:
  387.     case zoomDocProc:
  388.         result = true;
  389.         break;
  390.     }
  391.     return(result);
  392. }
  393.  
  394. /* true if window can be dragged */
  395. Boolean WinHasDrag(WindowPtr window)
  396. {
  397.     Boolean result = false;
  398.     
  399.     require(WinValid(window));
  400.     if (WinIsFloat(window))
  401.         result = WindoidHasDrag(window);
  402.     else switch (GetWVariant(window)) {
  403.     case documentProc:
  404.     case noGrowDocProc:
  405.     case zoomDocProc:
  406.     case zoomNoGrow:
  407.     case rDocProc:
  408.     case movableDBoxProc:
  409.         result = true;
  410.         break;
  411.     }
  412.     return(result);
  413. }
  414.  
  415. /* true if window can be zoomed */
  416. Boolean WinHasZoom(WindowPtr window)
  417. {
  418.     Boolean result = false;
  419.     
  420.     require(WinValid(window));
  421.     if (WinIsFloat(window))
  422.         result = WindoidHasZoom(window);
  423.     else switch (GetWVariant(window)) {
  424.     case zoomDocProc:
  425.     case zoomNoGrow:
  426.         result = true;
  427.         break;
  428.     }
  429.     return(result);
  430. }
  431.  
  432. /* true if the window has the input focus */
  433. Boolean WinHasFocus(WindowPtr window)
  434. {
  435.     return(window && window == FocusWindow());
  436. }
  437.  
  438. /* get window's title */
  439. void WinTitle(WindowPtr window, CStr255 title)
  440. {
  441.     require(WinValid(window));
  442.     require(StrValid(title, -1));
  443.     GetWTitle(window, (StringPtr) title);
  444.     p2cstr((StringPtr) title);
  445.     ensure(StrValid(title, sizeof(CStr255)));
  446. }
  447.  
  448. /* set window's title */
  449. void WinTitleSet(WindowPtr window, const char *title)
  450. {
  451.     Str255 ptitle;
  452.     
  453.     require(WinValid(window));
  454.     require(StrValid(title, sizeof(CStr255)));
  455.     c2pstr(strcpy((char*)ptitle, title));
  456.     SetWTitle(window, ptitle);
  457. }
  458.  
  459. /*----------------------------------------------------------------------------*/
  460. /* window layers */
  461. /*----------------------------------------------------------------------------*/
  462.  
  463. /* return window's extra data */
  464. static WindowExtraHandle winextra(WindowPtr window)
  465. {
  466.     return(window ? WinExtraHandle(window) : NULL);
  467. }
  468.  
  469. /* return next window in list */
  470. static WindowPtr winnext(WindowPtr window)
  471. {
  472.     WindowExtraHandle next = LLHNext(winextra(window));
  473.     return(next ? (**next).window : NULL);
  474. }
  475.  
  476. /* remove window from list */
  477. static WindowPtr windelete(WindowPtr head, WindowPtr item)
  478. {
  479.     WindowExtraHandle list = LLHDelete(winextra(head), winextra(item));
  480.     return(list ? (**list).window : NULL);
  481. }
  482.  
  483. /* insert window into list */
  484. static WindowPtr wininsert(WindowPtr head, WindowPtr item)
  485. {
  486.     WindowExtraHandle list = LLHInsert(winextra(head), winextra(item));
  487.     return(list ? (**list).window : NULL);
  488. }
  489.  
  490. /* return window's layer */
  491. WindowLayerType WinLayer(WindowPtr window)
  492. {
  493.     return(WinExtraPtr(window)->layer);
  494. }
  495.  
  496. /* set window's layer */
  497. void WinLayerSet(WindowPtr window, WindowLayerType layer)
  498. {
  499.     WindowLayerType oldlayer = WinLayer(window);
  500.  
  501.     require(WinLayerValid(layer));
  502.     gLayers[oldlayer] = windelete(gLayers[oldlayer], window);
  503.     WinExtraPtr(window)->layer = layer;
  504.     if (layer == WIN_LAYER_FLOAT)
  505.         WinHilite(window, true);
  506.     WinSelect(window);
  507. }
  508.  
  509. /*----------------------------------------------------------------------------*/
  510. /* Accessing the list of windows. These functions use our own private
  511.     array of window lists, in which each entry corresponds to a
  512.     window layer.  */
  513. /*----------------------------------------------------------------------------*/
  514.  
  515. /* return first window in layer */
  516. WindowPtr WinFirst(WindowLayerType layer)
  517. {
  518.     require(WinLayerValid(layer));
  519.     return(gLayers[layer]);
  520. }
  521.  
  522. /* return first visible window in layer */
  523. WindowPtr WinFirstVisible(WindowLayerType layer)
  524. {
  525.     WindowPtr window = NULL;
  526.     
  527.     require(WinLayerValid(layer));
  528.     window = WinFirst(layer);
  529.     while (window && ! WinVisible(window))
  530.         window = WinNext(window);
  531.     ensure(! window || WinVisible(window));
  532.     return(window);
  533. }
  534.  
  535. /* return next window in window's layer */
  536. WindowPtr WinNext(WindowPtr window)
  537. {
  538.     return(winnext(window));
  539. }
  540.  
  541. /* return next visible window in window's layer */
  542. WindowPtr WinNextVisible(WindowPtr window)
  543. {
  544.     do {
  545.         window = WinNext(window);
  546.     } while (window && ! WinVisible(window));
  547.     ensure(! window || WinVisible(window));
  548.     return(window);
  549. }
  550.  
  551. /* return the first visible non-floating window */
  552. WindowPtr WinFirstVisibleNonFloat(void)
  553. {
  554.     const WindowLayerType skip = WIN_LAYER_FLOAT;
  555.     WindowLayerType layer = WIN_LAYER_NONE;
  556.     WindowPtr window = NULL;
  557.     
  558.     for (layer = WIN_LAYER_LAST-1; ! window && layer >= WIN_LAYER_FIRST; --layer)
  559.         if (layer != skip)
  560.             window = WinFirstVisible(layer);
  561.     ensure(! window ||
  562.         (window == WinFirstVisible(WinLayer(window)) && ! WinIsFloat(window)));
  563.     return(window);
  564. }
  565.  
  566. /* return the next visible non-floating window */
  567. WindowPtr WinNextVisibleNonFloat(WindowPtr window)
  568. {
  569.     const WindowLayerType skip = WIN_LAYER_FLOAT;
  570.     WindowLayerType layer = WinLayer(window);
  571.     
  572.     if (layer == skip)
  573.         window = NULL;
  574.     else
  575.         window = WinNextVisible(window);
  576.     while (! window && layer >= WIN_LAYER_FIRST) {
  577.         if (layer != skip)
  578.             window = WinFirstVisible(layer);
  579.         --layer;
  580.     }    
  581.     ensure(! window || (WinVisible(window) && ! WinIsFloat(window)));
  582.     return(window);
  583. }
  584.  
  585. /*----------------------------------------------------------------------------*/
  586. /* displaying and selecting */
  587. /*----------------------------------------------------------------------------*/
  588.  
  589. /* return the window that a window should be sent behind of so as
  590.     to be the first window in the layer, or NULL if should be in front
  591.     of all other windows */
  592. static WindowPtr WinGetBehind(WindowLayerType layer)
  593. {
  594.     WindowLayerType nextlayer = layer + 1;
  595.     WindowPtr behind = NULL;
  596.     
  597.     require(WinLayerValid(layer));
  598.     while (nextlayer < WIN_LAYER_LAST && ! WinFirstVisible(nextlayer))
  599.         nextlayer++;
  600.     if (nextlayer < WIN_LAYER_LAST) {
  601.         behind = WinFirstVisible(nextlayer);
  602.         while (WinNextVisible(behind))
  603.             behind = WinNextVisible(behind);
  604.     }
  605.     ensure(! behind || WinValid(behind));
  606.     return(behind);
  607. }
  608.  
  609. /* send window behind another window */
  610. static void WinSendBehind(WindowPtr window, WindowPtr behind)
  611. {
  612.     RgnHandle exposedRgn;
  613.     WindowPeek wpeek = (WindowPeek) window;
  614.     WindowPeek win = NULL;
  615.     
  616.     require(WinValid(window));
  617.     require(! behind || WinVisible(behind));
  618.     require(window != behind);
  619.     exposedRgn = BeginRgn();
  620.     if (behind) {
  621.         win = wpeek->nextWindow;
  622.         while (win && win != (WindowPeek) behind)
  623.             win = win->nextWindow;
  624.     }
  625.     if (behind && ! win) /* moving window closer */
  626.         CopyRgn(window->visRgn, exposedRgn);
  627.     SendBehind(window, behind);
  628.     if (behind && ! win) {
  629.         /* Moved window closer. IM-I p286 recommends using:
  630.                 PaintOne(wpeek, wpeek->strucRgn);
  631.                 CalcVis(wpeek);
  632.             but that doesn't work well since the entire window's
  633.             content region is redrawn even though only the newly
  634.             exposed region needs redrawing. Also, the visRgn's
  635.             of the windows behind the window aren't updated
  636.             correctly. So, we use the following calls to
  637.             update the windows. */
  638.         PortToGlobalRgn(exposedRgn, window);
  639.         DiffRgn(wpeek->strucRgn, exposedRgn, exposedRgn);
  640.         PaintOne(wpeek, exposedRgn);
  641.         CalcVisBehind(wpeek, wpeek->strucRgn);
  642.     }
  643.     EndRgn(exposedRgn);
  644. }
  645.  
  646. /* prevent hiliting of our windows by the window manager */
  647. static pascal void PatchHiliteWindow(PatchType *patch, WindowPtr window, Boolean hilite)
  648. {
  649.     patch->skip = (((WindowPeek) window)->windowKind >= WIN_KIND_EXTRA);
  650. }
  651.  
  652. /* hilite the window */
  653. void WinHilite(WindowPtr window, Boolean hilite)
  654. {
  655.     PatchRemove(gPatchHiliteWindow);
  656.     HiliteWindow(window, hilite);
  657.     PatchInstall(gPatchHiliteWindow);
  658. }
  659.  
  660. /* move window to front of its layer */
  661. static void DoWinSelect(WindowPtr activate, WindowPtr const deactivate)
  662. {
  663.     WindowLayerType layer = WinLayer(activate);
  664.     WindowPtr behind = NULL;
  665.     
  666.     require(WinValid(activate));
  667.     require(! deactivate ||
  668.                 (! WinIsFloat(deactivate) &&
  669.                     (deactivate == FocusWindow() || WinIsSystem(deactivate))));
  670.     
  671.     /* program_note: should really be a precondition, but it's ok since
  672.         winshow selects the window; this is a temporary work-around till
  673.         i figure out how to get WinSendBehind to work with invisible
  674.         windows */
  675.     if (! WinVisible(activate)) return;
  676.     
  677.     /* make the window be the first window in its layer */
  678.     behind = WinGetBehind(layer);
  679.     if (behind && (WindowPtr)((WindowPeek)behind)->nextWindow != activate)
  680.         WinSendBehind(activate, behind);
  681.     else if (! behind && FrontWindow() != activate)
  682.         BringToFront(activate);
  683.     if (activate != WinFirst(layer))
  684.         gLayers[layer] = wininsert(windelete(gLayers[layer], activate), activate);
  685.  
  686.     check(activate == WinFirst(layer));
  687.  
  688.     if (WinVisible(activate)) {
  689.     
  690.         /* pass activate event to first non-floating window */
  691.         if (WinIsFloat(activate))
  692.             activate = WinNextVisibleNonFloat(activate);
  693.     
  694.         /* send system windows behind selected window */
  695.         if (deactivate && WinIsSystem(deactivate)) {
  696.             WindowPtr behind = activate;
  697.             WindowPtr system = deactivate;
  698.             HiliteWindow(deactivate, false);
  699.             while (system && WinIsSystem(system)) {
  700.                 WindowPtr next = (WindowPtr) ((WindowPeek) system)->nextWindow;
  701.                 WinSendBehind(system, behind);
  702.                 behind = system;
  703.                 system = next;
  704.             }
  705.         }
  706.         
  707.         /* Suppress activate event if a window has the input focus and it is
  708.             in a layer above the window that would be activated. This suppresses
  709.             the activate event, for instance, that would be generated for a
  710.             document window when a modal dialog is front most and the document
  711.             window is created behind it. */
  712.         if (activate && FocusWindow() && WinLayer(FocusWindow()) > WinLayer(activate))
  713.             activate = NULL;
  714.             
  715.         /* post activate events */
  716.         if (activate && activate != FocusWindow()) {
  717.             SetCurActivate(activate);
  718.             SetCurDeactive(deactivate);
  719.         }
  720.     }
  721. }
  722.  
  723. /* move window to front of its layer */
  724. void WinSelect(WindowPtr window)
  725. {
  726.     DoWinSelect(window, FocusWindow() ? FocusWindow() : SystemWindowActive());
  727. }
  728.  
  729. /* make the window invisible */
  730. void WinHide(WindowPtr window)
  731. {    
  732.     WindowPtr activate = NULL;
  733.     
  734.     require(WinValid(window));
  735.     if (WinVisible(window)) {
  736.         ShowHide(window, false);
  737.         if (window == FocusWindow()) {
  738.             activate = SystemWindowActive();
  739.             if (! activate)
  740.                 activate = WinNextVisibleNonFloat(window);
  741.             if (! activate || WinIsSystem(activate)) {
  742.                 if (activate)
  743.                     HiliteWindow(activate, true);
  744.                 FocusWindowSet(NULL);
  745.                 EventAdjustMenu();
  746.             }
  747.             else
  748.                 FocusWindowSet(activate);
  749.             SetCurActivate(activate);
  750.             SetCurDeactive(NULL);
  751.         }
  752.     }
  753.     ensure(! WinVisible(window));
  754. }
  755.  
  756. /* make the window visible and select it */
  757. void WinShow(WindowPtr window)
  758. {
  759.     require(WinValid(window));
  760.     if (! WinVisible(window)) {
  761.         WindowPtr deactivate = FocusWindow() ? FocusWindow() : SystemWindowActive();
  762.         if (WinIsModal(window)) {
  763.             WinHilite(window, true); /* prehiliting just looks better */
  764.             HiliteMenu(0); /* prevent menu bar flicker */
  765.         }
  766.         ShowHide(window, true);
  767.         DoWinSelect(window, deactivate);
  768.     }
  769.     ensure(WinVisible(window));
  770.     ensure(! WinHasDrag(window) ? WinVisibleFully(window) : WinCanDrag(window));
  771. }
  772.  
  773. /*----------------------------------------------------------------------------*/
  774. /* window rectangles */
  775. /*----------------------------------------------------------------------------*/
  776.  
  777. /* get the window's port rectangle */
  778. void WinPortRect(WindowPtr window, Rect *r)
  779. {
  780.     require(WinValid(window));
  781.     *r = window->portRect;
  782.     ensure(RectValid(r));
  783. }
  784.  
  785. /* Get the bounding rectangles for several window structures. These are
  786.     all merged into one function since calculating these rectangles for
  787.     an invisible window involves many redundant and slow calculations.
  788.     All rectangles are in global coordinates. */
  789. void WinRectangles(WindowPtr window,
  790.     Rect *structureRect,
  791.     Rect *contentRect,
  792.     Rect *dragRect,
  793.     Rect *newRect)
  794. {
  795.     require(WinValid(window));
  796.     
  797.     /* structure and content regions are
  798.         only valid if window is visible */
  799.     if (! WinVisible(window)) {
  800.         Point pt;
  801.         Rect windBBox;
  802.         Rect grayBBox;
  803.         grayBBox = (**GetGrayRgn()).rgnBBox;
  804.         WinPortRect(window, &windBBox);
  805.         RectPortToGlobal(&windBBox, window);
  806.         pt.h = grayBBox.left - RectWidth(&windBBox) - 512;
  807.         pt.v = grayBBox.top - RectHeight(&windBBox) - 512;
  808.         WinMove(window, pt.h, pt.v);
  809.         ShowHide(window, true);
  810.         *structureRect = (**((WindowPeek) window)->strucRgn).rgnBBox;
  811.         *contentRect = (**((WindowPeek) window)->contRgn).rgnBBox;
  812.         OffsetRect(structureRect, windBBox.left - pt.h, windBBox.top - pt.v);
  813.         OffsetRect(contentRect, windBBox.left - pt.h, windBBox.top - pt.v);
  814.         ShowHide(window, false);
  815.         WinMove(window, windBBox.left, windBBox.top);
  816.     }
  817.     else {
  818.         *structureRect = (**((WindowPeek) window)->strucRgn).rgnBBox;
  819.         *contentRect = (**((WindowPeek) window)->contRgn).rgnBBox;
  820.     }
  821.  
  822.     /* calculate drag rectangle (assumes adjacent to window, at least
  823.         5 pixels wide, and either on top or to left of window) */
  824.     SetRect(dragRect, 0, 0, 0, 0);
  825.     if (WinHasDrag(window)) {    
  826.         *dragRect = *structureRect;
  827.         if (structureRect->top + 5 < contentRect->top)
  828.             dragRect->bottom = contentRect->top; /* drag region above window */
  829.         else if (structureRect->left + 5 < contentRect->left)
  830.             dragRect->right = contentRect->left; /* drag region left of window */
  831.         InsetRect(dragRect, 1, 1);
  832.     }
  833.  
  834.     /* Calculate the largest rectangle (in global coordinates) for a new window.
  835.         The rectangle is completely contained on the current screen, and
  836.         excludes the menu bar, the window's title bar, and a few pixels from
  837.         each edge of the screen. */
  838.     ScreenGrayRect(newRect);
  839.     InsetRect(newRect, SCREEN_MARGIN, SCREEN_MARGIN);
  840.     newRect->top += contentRect->top - structureRect->top;
  841.     newRect->left += contentRect->left - structureRect->left;
  842.     newRect->bottom -= structureRect->bottom - contentRect->bottom;
  843.     newRect->right -= structureRect->right - contentRect->right;
  844.  
  845.     ensure(RectValid(structureRect));
  846.     ensure(RectValid(contentRect));
  847.     ensure(RectValid(dragRect));
  848.     ensure(RectValid(newRect));
  849.     ensure(RectWithin(contentRect, structureRect));
  850. }
  851.  
  852. void WinStructureRect(WindowPtr window, Rect *structure)
  853. {
  854.     Rect content, drag, new;
  855.     WinRectangles(window, structure, &content, &drag, &new);
  856. }
  857.  
  858. void WinContentRect(WindowPtr window, Rect *content)
  859. {
  860.     Rect structure, drag, new;
  861.     WinRectangles(window, &structure, content, &drag, &new);
  862. }
  863.  
  864. void WinDragRect(WindowPtr window, Rect *drag)
  865. {
  866.     Rect structure, content, new;
  867.     WinRectangles(window, &structure, &content, drag, &new);
  868. }
  869.  
  870. void WinNewRect(WindowPtr window, Rect *new)
  871. {
  872.     Rect structure, content, drag;
  873.     WinRectangles(window, &structure, &content, &drag, new);
  874. }
  875.  
  876. /*----------------------------------------------------------------------------*/
  877. /* window drawing */
  878. /*----------------------------------------------------------------------------*/
  879.  
  880. /*    This routine is similar to the Window Manager routine DrawGrowIcon,
  881.     except that it does not draw the lines enclosing the scroll bars. */
  882. void WinDrawGrowIcon(WindowPtr window)
  883. {
  884.     RgnHandle clip;
  885.     Handle sicn = NULL;
  886.     GrafPtr port= NULL;
  887.     PenState pen;
  888.     Rect grow;
  889.     Point pt;
  890.  
  891.     require(WinValid(window));
  892.     GetPort(&port);
  893.     SetPort(window);
  894.     GetPenState(&pen);
  895.     PenNormal();
  896.     clip = BeginRgn();
  897.     GetClip(clip);
  898.     WinPortRect(window, &grow);
  899.     grow.left = grow.right - 15;
  900.     grow.top = grow.bottom - 15;
  901.     ClipRect(&grow);
  902.     DrawGrowIcon(window);
  903.     SetClip(clip);
  904.     SetPenState(&pen);
  905.     SetPort(port);
  906.     EndRgn(clip);
  907.     ensure(WinValid(window));
  908. }
  909.  
  910. /*----------------------------------------------------------------------------*/
  911. /* window creation and destruction */
  912. /*----------------------------------------------------------------------------*/
  913.  
  914. /* create the extra window data and register the window so it receives
  915.     events */
  916. void WinInitialize(WindowPtr window, WindowLayerType layer)
  917. {
  918.     WindowExtraHandle extra = NULL;
  919.     
  920.     require(! WinVisible(window));
  921.     TRY {
  922.         extra = HandleBeginClear(sizeof(WindowExtraType));
  923.         if (WinKind(window) == dialogKind)
  924.             (**extra).dialog = true;
  925.         WinKindSet(window, WIN_KIND_EXTRA);
  926.         WinExtraSet(window, extra);
  927.         WinRegister(window, window, WinEventTable());
  928.         WinLayerSet(window, layer);
  929.     } CATCH {
  930.         WinUninitialize(window);
  931.     } ENDTRY;
  932. }
  933.  
  934. /* unregister the window and dispose of the extra data */
  935. void WinUninitialize(WindowPtr window)
  936. {
  937.     require(WinValid(window));
  938.     if (WinHasExtra(window)) {
  939.         gLayers[WinLayer(window)] = windelete(gLayers[WinLayer(window)], window);
  940.         WinUnregister(window, window);
  941.         check(WinExtraPtr(window)->objects == NULL);
  942.         HandleEnd(WinExtraPtr(window)->tablist);
  943.         HandleEnd(WinExtraHandle(window));
  944.         SetWRefCon(window, 0L);
  945.     }
  946. }
  947.  
  948. /* Adjust the window template and return window behind which the
  949.     window created based from the template should be sent. The new window's
  950.     layer is returned in the 'layer' parameter. This function is used only
  951.     before creating a window or dialog. */
  952. WindowPtr WinAdjustTemplate(WindowTemplate *wind, WindowLayerType *layer)
  953. {
  954.     static Boolean installed;        /* true if installed patch */
  955.     WindowPtr behind = NULL;        /* create window behind this window */
  956.     short wdefID = 0;                    /* id of wdef */
  957.     short varID = 0;                    /* window's variation code */
  958.  
  959.     /* install patch */
  960.     if (! installed) {
  961.         gPatchHiliteWindow =
  962.             PatchBegin(PatchHiliteWindow, _HiliteWindow,
  963.                 sizeof(WindowPtr) + sizeof(PatchBooleanParameter), 0, NULL);
  964.         installed = true;
  965.     }
  966.     
  967.     /* determine window layer */
  968.     wdefID = (wind->procID >> 4);
  969.     varID = (wind->procID & 0x000F);
  970.     if (wdefID == RLWDEF_FLOAT)
  971.         *layer = WIN_LAYER_FLOAT;
  972.     else if (varID == dBoxProc || varID == movableDBoxProc)
  973.         *layer = WIN_LAYER_MODAL;
  974.     else
  975.         *layer = WIN_LAYER_DOCUMENT;
  976.     behind = WinGetBehind(*layer);
  977.     if (! behind)
  978.         behind = (WindowPtr) -1L;
  979.         
  980.     /* for compatability with systems prior to 7.0, use special WDEF
  981.         for movable modal dialogs */
  982.     if (MacVersion() < 0x0700 && wind->procID == movableDBoxProc)
  983.         wind->procID += RLWDEF_MOVABLE_MODAL * 16;
  984.  
  985.     return(behind);
  986. }
  987.  
  988. /* create a new window from the window template */
  989. static WindowPtr WinBeginTemplate(WindowTemplate *wind)
  990. {
  991.     WindowPtr behind = NULL;                /* create window behind this window */
  992.     WindowLayerType layer = 0;                /* new window's layer */
  993.     volatile WindowPtr window = NULL;    /* the new window */
  994.     
  995.     require(RectValid(&wind->boundsRect));
  996.     TRY {
  997.         behind = WinAdjustTemplate(wind, &layer);
  998.         MemCheck(sizeof(WindowRecord));
  999.         if (MacHasColor()) {
  1000.             window = NewCWindow(NULL, &wind->boundsRect, wind->title, false,
  1001.                             wind->procID, behind, wind->goAwayFlag, wind->refCon);
  1002.         }
  1003.         else {
  1004.             window = NewWindow(NULL, &wind->boundsRect, wind->title, false,
  1005.                             wind->procID, behind, wind->goAwayFlag, wind->refCon);
  1006.         }
  1007.         FailNIL(window);
  1008.         WinInitialize(window, layer);
  1009.     } CATCH {
  1010.         WinEnd(window);
  1011.     } ENDTRY;
  1012.     ensure(! WinVisible(window));
  1013.     return(window);
  1014. }
  1015.  
  1016. /* create a new invisible window using the specified 'WIND' resource */
  1017. WindowPtr WinGet(short id)
  1018. {
  1019.     WindowTemplate wind;
  1020.     
  1021.     ResPtr('WIND', id, &wind, sizeof(WindowTemplate));
  1022.     return(WinBeginTemplate(&wind));
  1023. }
  1024.  
  1025. /* create a new invisible window */
  1026. WindowPtr WinBegin(short procID, Boolean goAwayFlag)
  1027. {
  1028.     WindowTemplate wind;
  1029.     
  1030.     memclr(&wind, sizeof(WindowTemplate));
  1031.     SetRect(&wind.boundsRect, 0, 0, 100, 100);
  1032.     wind.procID = procID;
  1033.     wind.goAwayFlag = goAwayFlag;
  1034.     return(WinBeginTemplate(&wind));
  1035. }
  1036.  
  1037. /* dispose of the window */
  1038. void WinEnd(WindowPtr window)
  1039. {
  1040.     if (window) {
  1041.         WinHide(window);
  1042.         WinUninitialize(window);
  1043.         DisposeWindow(window);
  1044.         window = NULL;
  1045.     }
  1046.     ensure(! WinValid(window));
  1047. }
  1048.  
  1049. /*----------------------------------------------------------------------------*/
  1050. /* event handling */
  1051. /*----------------------------------------------------------------------------*/
  1052.  
  1053. /* activate/deactivate the window */
  1054. void WinActivate(WindowPtr window, Boolean active)
  1055. {
  1056.     require(WinValid(window));
  1057.     WinHilite(window, active);
  1058.     if (WinHasGrow(window))
  1059.         WinDrawGrowIcon(window);
  1060.     ensure(WinValid(window));
  1061. }
  1062.  
  1063. /* hide all windows in layer from back to front to minimize redrawing */
  1064. static void WinHideLayer(WindowPtr window)
  1065. {
  1066.     if (window) {
  1067.         WinHideLayer(WinNext(window));
  1068.         if (WinVisible(window))
  1069.             WinExtraPtr(window)->visible = true;
  1070.         else
  1071.             WinExtraPtr(window)->visible = false;
  1072.         ShowHide(window, false);
  1073.     }
  1074. }
  1075.  
  1076. /* show all windows in layer from front to back to minimize redrawing */
  1077. static void WinShowLayer(WindowPtr window)
  1078. {
  1079.     while (window) {
  1080.         if (WinExtraPtr(window)->visible)
  1081.             ShowHide(window, true);
  1082.         window = WinNext(window);
  1083.     }
  1084. }
  1085.  
  1086. /* handle suspend event */
  1087. void WinSuspend(void)
  1088. {
  1089.     WinHideLayer(WinFirst(WIN_LAYER_FLOAT));
  1090.     EventActivate(FocusWindow(), false);
  1091. }
  1092.  
  1093. /* handle resume event */
  1094. void WinResume(void)
  1095. {
  1096.     WinShowLayer(WinFirst(WIN_LAYER_FLOAT));
  1097.     EventActivate(FocusWindow(), true);
  1098. }
  1099.  
  1100. /* update the window */
  1101. void WinUpdate(WindowPtr window)
  1102. {
  1103.     require(WinValid(window));
  1104.     if (WinHasGrow(window))
  1105.         WinDrawGrowIcon(window);
  1106.     if (WinIsDialog(window))
  1107.         UpdtDialog(window, window->visRgn);
  1108.     else
  1109.         UpdtControl(window, window->visRgn);
  1110.     ensure(WinValid(window));
  1111. }
  1112.